package com.liliudong.rommath.biz.sys.service.impl;


import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.liliudong.rommath.biz.sys.entity.SysDept;
import com.liliudong.rommath.biz.sys.mapper.SysDeptMapper;
import com.liliudong.rommath.biz.sys.param.SysDeptAddParam;
import com.liliudong.rommath.biz.sys.param.SysDeptModifyParam;
import com.liliudong.rommath.biz.sys.service.SysDeptService;
import com.liliudong.rommath.biz.sys.service.SysUserService;
import com.liliudong.rommath.common.consts.RommathConst;
import com.liliudong.rommath.common.exception.BizException;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

import static com.liliudong.rommath.biz.sys.entity.table.SysDeptTableDef.SYS_DEPT;
import static com.liliudong.rommath.biz.sys.entity.table.SysUserTableDef.SYS_USER;

/**
 * 系统部门 服务层实现。
 *
 * @author liudong.li
 * @since 1.0.0
 */
@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {

    private final SysUserService sysUserService;

    @Override
    public void add(SysDeptAddParam param) {
        String code = param.getCode();
        String name = param.getName();
        String parentCode = param.getParentCode();
        String description = param.getDescription();

        long countByCode = queryChain().where(SYS_DEPT.CODE.eq(code)).count();
        if (countByCode > 0) {
            throw new BizException("部门编码重复");
        }

        // 同级部门名称不能重复
        long countByName = queryChain()
                .where(SYS_DEPT.NAME.eq(name)
                        .and(SYS_DEPT.PARENT_CODE.eq(parentCode, StrUtil.isNotBlank(parentCode)))
                        .and(SYS_DEPT.PARENT_CODE.isNull(StrUtil.isBlank(parentCode)))
                )
                .count();
        if (countByName > 0) {
            throw new BizException("同级部门名称不能重复");
        }

        SysDept sysDept = new SysDept();
        sysDept.setCode(code);
        sysDept.setName(name);
        sysDept.setParentCode(parentCode);
        sysDept.setDescription(description);
        save(sysDept);
    }

    @Override
    public void delete(Long id) {
        SysDept sysDept = getById(id);
        if (Objects.isNull(sysDept)) {
            throw new BizException("部门不存在");
        }

        // 存在子级不能删除
        long count = queryChain().where(SYS_DEPT.PARENT_CODE.eq(sysDept.getCode())).count();
        if (count > 0) {
            throw new BizException("存在子级不能删除");
        }
        // 存在用户不能删除
        long userCount = sysUserService.queryChain()
                .from(SYS_USER)
                .where(SYS_USER.DEPT_CODE.eq(sysDept.getCode()))
                .count();
        if (userCount > 0) {
            throw new BizException("部门下存在用户不能删除");
        }

        removeById(id);
    }

    @Override
    public void modify(SysDeptModifyParam param) {
        String code = param.getCode();
        String name = param.getName();
        String parentCode = param.getParentCode();
        String description = param.getDescription();

        SysDept sysDept = queryChain().where(SYS_DEPT.CODE.eq(code)).one();
        if (Objects.isNull(sysDept)) {
            throw new BizException("部门不存在");
        }

        // 同级部门名称不能重复
        long countByName = queryChain()
                .where(SYS_DEPT.NAME.eq(name)
                        .and(SYS_DEPT.PARENT_CODE.eq(parentCode, StrUtil.isNotBlank(parentCode)))
                        .and(SYS_DEPT.PARENT_CODE.isNull(StrUtil.isBlank(parentCode)))
                        .and(SYS_DEPT.CODE.ne(sysDept.getCode()))
                )
                .count();
        if (countByName > 0) {
            throw new BizException("同级部门名称不能重复");
        }

        sysDept.setName(name);
        sysDept.setParentCode(parentCode);
        sysDept.setDescription(description);
        updateById(sysDept);
    }

    @Override
    public List<Tree<String>> tree() {
        List<TreeNode<String>> treeNodes = list().stream()
                .map(sysDept -> new TreeNode<>(sysDept.getCode(), sysDept.getParentCode(), sysDept.getName(), 0))
                .toList();
        return TreeUtil.build(treeNodes, RommathConst.ROOT_DEPT_CODE);
    }
}